﻿using System;
using System.Collections.Generic;
using Ornament.MemberShip;
using Ornament.Messages.Contents;
using Ornament.Messages.Contents.Stores;
using Ornament.Messages.Dao;

namespace Ornament.Messages
{
    public class InfoManager
    {
        private IDictionary<Type, IStore> storeTypes;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="storeTypes">Type is the type of dirver from <see cref="Content"/>,StoreType</param>
        /// <param name="factory"></param>
        public InfoManager(IDictionary<Type, IStore> storeTypes, IDaoFactory factory)
        {
            if (storeTypes.Count == 0)
            {
                throw new ArgumentOutOfRangeException("storeTypes", "storeTypes is empty");
            }
            if (factory == null)
                throw new ArgumentNullException("factory");
            this.storeTypes = storeTypes;
            Factory = factory;
        }

        /// <summary>
        /// 
        /// </summary>
        public IDaoFactory Factory { get; private set; }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <param name="content"></param>
        /// <param name="publisher"></param>
        /// <returns></returns>
        public Info CreateInfo<T>(InfoType type, T content, string publisher)
        {
            var info = new Info(publisher, type) {Content = CreateContent<T>(content)};
            return info;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="typeName"></param>
        /// <param name="content"></param>
        /// <param name="publisher"></param>
        /// <returns></returns>
        public Info CreateInfo<T>(string typeName, T content, string publisher)
        {
            var infoType = Factory.InfoTypeDao.Get(typeName);
            return this.CreateInfo<T>(infoType, content, publisher);
        }

        public void Save(Info message)
        {
            Factory.InfoDao.SaveOrUpdate(message);
        }

        public void SetReadState(ReadStatus status, Guid infoId, User user)
        {
            Info info = Factory.InfoDao.Get(infoId);
            var stateDao = Factory.InfoReadStateDao;

            InfoReadState infoState = stateDao.Get(user, info) ?? new InfoReadState(user, info);

            infoState.Status = status;

            Factory.InfoReadStateDao.SaveOrUpdate(infoState);
        }

        public void Delete(Info message)
        {
            Factory.InfoDao.Delete(message);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="content"></param>
        /// <returns></returns>
        private GenericContent<T> CreateContent<T>(T content)
        {
            var contentObj = new GenericContent<T>();
            contentObj.Store = GetStoreType(typeof(T));
            contentObj.Value = content;
            return contentObj;
        }


        private IStore GetStoreType(Type contentType)
        {
            if (!storeTypes.ContainsKey(contentType))
            {
                throw new ArgumentException(contentType.Name + " can't found any store type,please specify one.");
            }
            return storeTypes[contentType];
        }
    }
}